package ophiux.wechatpay.sdk.common.parse;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import ophiux.wechatpay.sdk.OphiuxWeChatPaySDKException;
import ophiux.wechatpay.sdk.common.utils.DataTypeUtil;
import ophiux.wechatpay.sdk.common.writer.MapWriter;
import ophiux.wechatpay.sdk.common.writer.Writer;

public class EntityConverter {

	public static <T> T convert(Class<T> clzz,Reader reader) throws OphiuxWeChatPaySDKException {
		
		T entity = null;
		//判断目标类clzz是否为空
		if(clzz == null){
			throw new OphiuxWeChatPaySDKException("target class is null");
		}
		try {
			entity = clzz.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
			throw new OphiuxWeChatPaySDKException(e);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			throw new OphiuxWeChatPaySDKException(e);
		}
		List<Field> fieldList = new ArrayList<Field>();
		Class<?> temp_clzz =  entity.getClass();
	 	while(temp_clzz != null){
//			fieldList.addAll(Arrays.asList(temp_clzz.getClass().getSuperclass().getDeclaredFields()));
			fieldList.addAll(Arrays.asList(temp_clzz.getDeclaredFields()));
			temp_clzz = temp_clzz.getSuperclass();
	 	}
	//	Field[] fields = entity.getClass().getFields();
	 //	Field f = entity.getClass().getDeclaredField("");
//		List<Field> writeableFieldList = new ArrayList<Field>();
	//	Class<? extends Annotation> ruleClzz = reader.getReaderRuleAnnotation();
		for(Field field : fieldList){
		//	Field field = fields[i];
			
			FieldKey annotation = field.getAnnotation(FieldKey.class);
			ListFieldKey listAnnotation = field.getAnnotation(ListFieldKey.class);
			if(annotation == null){
				continue;
			}
			String tagName = annotation.value();
			String parentTagName = "";
			if(listAnnotation != null){
				parentTagName = listAnnotation.value();
				if(!reader.isExistNode(parentTagName)){
					continue;
				}
			}else{
				if(!reader.isExistNode(tagName)){
					continue;
				}
			}
			
			Class<?> fieldType = field.getType();
			try {
				field.setAccessible(true);
				if(String.class.isAssignableFrom(fieldType)){
					Object value = reader.getNodeValue(tagName);
					field.set(entity, value);
					
				}else if(DataTypeUtil.isLong(fieldType)){
					Object value = reader.getNodeValue(tagName);
					if(DataTypeUtil.isLongValue(value)){
						field.set(entity,Long.parseLong(value+""));
					}else{
						throw new OphiuxWeChatPaySDKException(tagName+" not long"); 
					}
				}else if(DataTypeUtil.isInteger(fieldType)){
					Object value = reader.getNodeValue(tagName);
					if(DataTypeUtil.isIntegerValue(value)){
						field.set(entity,Integer.parseInt(value+""));
					}else{
						throw new OphiuxWeChatPaySDKException(tagName+" not int"); 
					}
				}else if(DataTypeUtil.isDouble(fieldType)){
					Object value = reader.getNodeValue(tagName);
					if(DataTypeUtil.isDoubleValue(value)){
						field.set(entity, Double.parseDouble(value+""));
					}else{
						throw new OphiuxWeChatPaySDKException(tagName+" not double"); 
					}
				}else if(DataTypeUtil.isFloat(fieldType)){
					Object value = reader.getNodeValue(tagName);
					if(DataTypeUtil.isFloatValue(value)){
						field.set(entity,Float.parseFloat(value+""));
					}else{
						throw new OphiuxWeChatPaySDKException(tagName+" not double"); 
					}
				}else if(DataTypeUtil.isBoolean(fieldType)){
					Object value = reader.getNodeValue(tagName);
					if(DataTypeUtil.isBooleanValue(value)){
						field.set(entity,Boolean.parseBoolean(value+""));
					}else{
						throw new OphiuxWeChatPaySDKException(tagName+" not boolean"); 
					}
				}else if(List.class.isAssignableFrom(fieldType)){
					Type genericType = field.getGenericType();
					if(genericType instanceof ParameterizedType){
						ParameterizedType trueType = (ParameterizedType)genericType;
						Class<?> subClzzType = (Class<?>) 
								trueType.getActualTypeArguments()[0];
						List<?> list = reader.getNodeListObject(parentTagName,tagName,subClzzType);
						field.set(entity, list);
					}else{
						
					}
					
				}else{
					Object value = reader.getNodeObject(tagName, fieldType);
					field.set(entity, value);
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
				throw new OphiuxWeChatPaySDKException(e);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
				throw new OphiuxWeChatPaySDKException(e);
			}
		}
		
		return entity;
	}
	
	
	public static <T> String writerToString(T obj,Writer writer) throws OphiuxWeChatPaySDKException{
		
		if(obj == null){
			throw new OphiuxWeChatPaySDKException("convert class is null");
		}
		
		Field[] fields = obj.getClass().getDeclaredFields();
		String target = "";
		for(int i=0;i<fields.length;i++){
			Field field = fields[i];
			try {
				field.setAccessible(true);//设置操作权限
				FieldKey fieldKey = field.getAnnotation(FieldKey.class);
				ListFieldKey listFieldKey = field.getAnnotation(ListFieldKey.class);
				if(fieldKey == null){
					continue;
				}
				Class clzzType = field.getType();
				Type type = field.getGenericType();
				 
				if(String.class.isAssignableFrom(clzzType)
				   || DataTypeUtil.isBoolean(clzzType)
				   || DataTypeUtil.isDouble(clzzType)
				   || DataTypeUtil.isFloat(clzzType)
				   || DataTypeUtil.isInteger(clzzType)
				   || DataTypeUtil.isLong(clzzType)
				  ){
					Object value = field.get(obj);
					target += writer.writerFromString(value, fieldKey.value());
				}else if(List.class.isAssignableFrom(clzzType)){
					if(listFieldKey == null){
						continue;
					}
					List value = (List) field.get(obj);
					target += writer.writerFromArray(value,listFieldKey.value(),fieldKey.value());
				}else{
					Object value = field.get(obj);
					target += writer.writerFromObject(value,fieldKey.value());
				}
			} catch (IllegalArgumentException e) {
				throw new OphiuxWeChatPaySDKException(e);
				
			} catch (IllegalAccessException e) {
				throw new OphiuxWeChatPaySDKException(e);
			}
		}
		return target;
		
	}
	
	/**
	 * 将对象转为map
	 * @author hhl
	 * @param obj
	 * @param writer
	 * @return
	 * @throws OphiuxWeChatPaySDKException
	 */
	public static <T> SortedMap writer2Map(T obj,MapWriter writer) throws OphiuxWeChatPaySDKException{
		SortedMap<String, Object> targetMap = new TreeMap<String, Object>();
		if(obj == null){
			throw new OphiuxWeChatPaySDKException("convert class is null");
		}
		
		Field[] fields = obj.getClass().getDeclaredFields();
		String target = "";
		for(int i=0;i<fields.length;i++){
			Field field = fields[i];
			try {
				field.setAccessible(true);//设置操作权限
				FieldKey fieldKey = field.getAnnotation(FieldKey.class);
				ListFieldKey listFieldKey = field.getAnnotation(ListFieldKey.class);
//				if(fieldKey == null){
//					continue;
//				}
				Class clzzType = field.getType();
				Type type = field.getGenericType();
				 
				if(String.class.isAssignableFrom(clzzType)
				   || DataTypeUtil.isBoolean(clzzType)
				   || DataTypeUtil.isDouble(clzzType)
				   || DataTypeUtil.isFloat(clzzType)
				   || DataTypeUtil.isInteger(clzzType)
				   || DataTypeUtil.isLong(clzzType)
				  ){
					Object value = field.get(obj);
				//	target += writer.writerFromString(value, fieldKey.value());
					targetMap.put(field.getName(), value);
				}else if(List.class.isAssignableFrom(clzzType)){
//					if(listFieldKey == null){
//						continue;
//					}
					List value = (List) field.get(obj);
					SortedMap<String,Object> ListMap =  writer.writerFromArray(value);
					targetMap.putAll(ListMap);
				}else{
					Object value = field.get(obj);
					if(value!=null){
						SortedMap<String,Object> objMap =  writer.writerFromObject(value);
						targetMap.putAll(objMap);
					}
				}
			} catch (IllegalArgumentException e) {
				throw new OphiuxWeChatPaySDKException(e);
				
			} catch (IllegalAccessException e) {
				throw new OphiuxWeChatPaySDKException(e);
			}
		}
		return targetMap;
		
	}
	
}
